set(CURRENT_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR})
set(ROS_DEVEL_DIR "${CATKIN_DEVEL_PREFIX}")
set(ROS_CPP_H_DEVEL_DIR "${ROS_DEVEL_DIR}/include/")
set(ROS_PYTHON_DEVEL_DIR "${ROS_DEVEL_DIR}/lib/python2.7/dist-packages")
# set(PROTOBUF_PROTOC_EXECUTABLE  ${Protobuf_PROTOC_EXECUTABLE} )
set(PROTOBUF_PROTOC_EXECUTABLE  /opt/libs-x86_64-Linux/protobuf/protobuf-3.13.0.1/bin/protoc )

#  ----------以下是将proto转为ros对接用msg的脚本----------

# 基础函数，根据proto生成的py文件,生成对接ros的cpp和python代码
function(generate_proto_ros_bridge msg_type)
  set(PROTOBUF_ROS_EXECUTABLE "${CURRENT_CMAKE_DIR}/ProtobufROSGen.py")

  set(proto_list ${ARGN})

  # 遍历proto
  foreach(proto_file ${proto_list})
    get_filename_component(FILE_ABS ${proto_file} ABSOLUTE)   # 文件绝对路径
    get_filename_component(FILE_WE ${proto_file} NAME_WE)      # 不带扩展名的文件名

    add_custom_target(ros_proto_${FILE_WE} ALL
      DEPENDS ${proto_list})

    add_custom_command(
      TARGET ros_proto_${FILE_WE}
      COMMAND ${PROTOBUF_ROS_EXECUTABLE}
      ARGS ${msg_type} ${FILE_ABS} ${ROS_DEVEL_DIR}
      DEPENDS ${FILE_ABS} ${PROTOBUF_ROS_EXECUTABLE} ${proto_list}
      COMMENT "Generating ROS bridge for proto: ${proto_file}"
      VERBATIM
    )
  endforeach()
endfunction()

# 生成msg对接ros的代码
function(generate_proto_ros_msg)
    generate_proto_ros_bridge("msg"  ${ARGN})
endfunction()

# 生成srv对接ros的代码
function(generate_proto_ros_srv)
    generate_proto_ros_bridge("srv"  ${ARGN})
endfunction()

# 生成action对接ros的代码
function(generate_proto_ros_action)
  GENERATE_PROTO_ROS_BRIDGE("action" ${ARGN})
endfunction()

#  ----------以下是将proto转为cpp的脚本----------

# 基础函数，生成proto的cpp代码
function(generate_proto_cpp msg_type out_srcs out_hdrs)
    set(proto_files ${ARGN})
    set(output_root_dir "${ROS_CPP_H_DEVEL_DIR}/${PROJECT_NAME}")
    foreach(proto_file_name ${proto_files})
      if(NOT proto_file_name MATCHES "^/")
        # 如果不以 / 开头，拼接前缀路径
        set(proto_file "${CMAKE_CURRENT_SOURCE_DIR}/proto/${PROJECT_NAME}/${msg_type}/${proto_file_name}")
      else()
          # 如果以 / 开头，保留原样
          set(proto_file "${proto_file_name}")
      endif()

        get_filename_component(FILE_NAME ${proto_file} NAME_WE)
        get_filename_component(FILE_DIR ${proto_file} DIRECTORY)

        set(output_file_dir "${output_root_dir}")

        # 检查并创建输出目录
        if(NOT EXISTS ${output_file_dir})
          file(MAKE_DIRECTORY ${output_file_dir})
        endif()

        # 定义输出文件的完整路径
        set(OUTPUT_CC "${output_file_dir}/${msg_type}/${FILE_NAME}.pb.cc")
        set(OUTPUT_H "${output_file_dir}/${msg_type}/${FILE_NAME}.pb.h")
        set(OUTPUT_PY "${ROS_PYTHON_DEVEL_DIR}/${PROJECT_NAME}/${msg_type}/${FILE_NAME}_pb2.py")

        # 使用自定义命令生成 .pb.cc 和 .pb.h 文件
        add_custom_command(
            OUTPUT 
                ${OUTPUT_CC}
                ${OUTPUT_H}
            COMMAND  ${PROTOBUF_PROTOC_EXECUTABLE}
            ARGS 
                --cpp_out ${ROS_CPP_H_DEVEL_DIR}
                --proto_path  ${PROTO_ROOT_DIR}
                -I ${PROTO_ROOT_DIR}
                -I ${PROTO_ROOT_DIR}/msg
                -I ${PROTO_ROOT_DIR}/srv
                -I ${PROTO_ROOT_DIR}/action
                ${proto_file}
            DEPENDS ${proto_file} ${OUTPUT_PY}
            COMMENT "Running C++ protocol buffer compiler on ${proto_file}"
            VERBATIM
        )

        # 将生成的文件路径添加到传出的列表中
        list(APPEND _out_srcs ${OUTPUT_CC})
        list(APPEND _out_hdrs ${OUTPUT_H})
    endforeach()

    # 设置生成的源文件和头文件属性
    set_source_files_properties(${_out_srcs} ${_out_hdrs} PROPERTIES GENERATED TRUE)

    # 设置传出变量的值
    set(${out_srcs} ${_out_srcs} PARENT_SCOPE)
    set(${out_hdrs} ${_out_hdrs} PARENT_SCOPE)
endfunction()

# 生成msg的cpp代码
function(generate_proto_cpp_msg out_srcs out_hdrs)
  generate_proto_cpp("msg" _out_srcs _out_hdrs ${ARGN})

  set(${out_srcs} ${_out_srcs} PARENT_SCOPE)
  set(${out_hdrs} ${_out_hdrs} PARENT_SCOPE)
endfunction()

# 生成srv的cpp代码
function(generate_proto_cpp_srv out_srcs out_hdrs)
  generate_proto_cpp("srv"  _out_srcs _out_hdrs ${ARGN})

  set(${out_srcs} ${_out_srcs} PARENT_SCOPE)
  set(${out_hdrs} ${_out_hdrs} PARENT_SCOPE)
endfunction()

# 生成action的cpp代码
function(generate_proto_cpp_action out_srcs out_hdrs)
  generate_proto_cpp("action"  _out_srcs _out_hdrs ${ARGN})

  set(${out_srcs} ${_out_srcs} PARENT_SCOPE)
  set(${out_hdrs} ${_out_hdrs} PARENT_SCOPE)
endfunction()


#  ----------以下是将proto转为python的脚本----------

# 基础函数，生成proto的python代码
function(generate_proto_python msg_type out_py_files)
    # 处理输入参数
    set(proto_files ${ARGN})
    set(output_root_dir "${ROS_PYTHON_DEVEL_DIR}/${PROJECT_NAME}")
    foreach(proto_file_name ${proto_files})
        if(NOT proto_file_name MATCHES "^/")
          # 如果不以 / 开头，拼接前缀路径
          set(proto_file "${CMAKE_CURRENT_SOURCE_DIR}/proto/${PROJECT_NAME}/${msg_type}/${proto_file_name}")
        else()
            # 如果以 / 开头，保留原样
            set(proto_file "${proto_file_name}")
        endif()
        get_filename_component(FILE_NAME ${proto_file} NAME_WE)
        get_filename_component(FILE_DIR ${proto_file} DIRECTORY)

        set(output_file_dir "${output_root_dir}")

        # 检查并创建输出目录
        if(NOT EXISTS ${output_file_dir})
          file(MAKE_DIRECTORY ${output_file_dir})
        endif()

        # 定义输出文件的完整路径
        set(OUTPUT_PY "${output_file_dir}/${msg_type}/${FILE_NAME}_pb2.py")
        # 使用自定义命令生成 .py 文件
        add_custom_command(
            OUTPUT ${OUTPUT_PY}
            COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
            ARGS 
                --python_out ${ROS_PYTHON_DEVEL_DIR}
                --proto_path  ${PROTO_ROOT_DIR}
                -I ${PROTO_ROOT_DIR}
                -I ${PROTO_ROOT_DIR}/msg
                -I ${PROTO_ROOT_DIR}/srv
                -I ${PROTO_ROOT_DIR}/action
                ${proto_file}
            DEPENDS ${proto_file}
            COMMENT "Running Python protocol buffer compiler on ${proto_file}"
            VERBATIM
        )

        # 将生成的文件路径添加到传出的列表中
        list(APPEND _out_py_files ${OUTPUT_PY})
    endforeach()

    # 设置生成的 Python 文件属性
    set_source_files_properties(${_out_py_files} PROPERTIES GENERATED TRUE)

    # 设置传出变量的值
    set(${out_py_files} ${_out_py_files} PARENT_SCOPE)
endfunction()


# 生成msg的python代码
function(generate_proto_python_msg out_py_files)
  generate_proto_python("msg" _out_py_files ${ARGN})

  set(${out_py_files} ${_out_py_files} PARENT_SCOPE)
endfunction()

# 生成srv的python代码
function(generate_proto_python_srv out_py_files)
  generate_proto_python("srv" _out_py_files ${ARGN})

  set(${out_py_files} ${_out_py_files} PARENT_SCOPE)
endfunction()

# 生成action的python代码
function(generate_proto_python_action out_py_files)
  generate_proto_python("action" _out_py_files ${ARGN})

  set(${out_py_files} ${_out_py_files} PARENT_SCOPE)
endfunction()

# 获取proto中定义的包名称
function(get_proto_package proto_file proto_package)
     # 读取 .proto 文件内容
     file(READ ${proto_file} proto_content)

  # 使用正则表达式匹配 package 声明
  string(REGEX MATCH "package[ \t]+([a-zA-Z0-9_.]+)[ \t]*;?" package_match ${proto_content})

  # 提取包名
  if(package_match)
      string(REGEX REPLACE "package[ \t]+([a-zA-Z0-9_.]+)[ \t]*;?" "\\1" package_name ${package_match})
      set(${proto_package} ${package_name} PARENT_SCOPE)
  else()
      set(${proto_package} "" PARENT_SCOPE)
  endif()
endfunction()
